#ifndef ARBOLB_H_
#define ARBOLB_H_
//#include "Tipos.h"
//#include "NodoBase.h"
#include "ArchivoIndice.h"


using namespace std;


template <class CClave>
class CArbolB
{
private:
	MapNodo			m_rama;
	TIPO_DATO		m_posRama;//posicion del bloque dentro de la rama 
	TIPO_DATO		m_cantBloques; //cantidad de bloques que tiene el arbol
	TIPO_DATO		m_posModificado;//posicion desde la cual se modifico los nodos de la rama
	bool 			m_hrnoDerecho;
	CClave			m_claveAux;
	CClave			m_claveIn;
	int recursivo;
	TIPO_DATO		m_siguiente;
	CArchivoIndice<CClave > m_archIndice; //archivo que guarda el indice en el disco
	fstream			m_archivoListaSec;
	bool			m_encontro; //informa si se encontro la clave cuando se quiere obtener la misma.

	TIPO_DATO		m_tamanioArchivo;
	TIPO_DATO		m_posRamaAux;
	int				m_costoProceso; //(CTO_PROC)
	
	bool insertarClave(CClave& clave);
	void redistribuirRaiz(TIPO_DATO nivel,CClave &clave);
	void recorreEnOrden(TIPO_DATO &bloque);
	void intercambioClaves(CClave& clave);
	void intercambiarIzquierdo();
	void podarRama(TIPO_DATO posRama);
	
	TIPO_DATO resolverUnderflow(TIPO_DATO posRama);
	bool hrnoConElemento(TIPO_DATO posRama,TIPO_DATO &posRamaHrno,TIPO_DATO &posPadre);
  	bool hrnoParaFusionar(TIPO_DATO &posRama,TIPO_DATO &posRamaHrno,TIPO_DATO &posPadre);
	void fusionar(TIPO_DATO &posRama,TIPO_DATO posRamaHrno,TIPO_DATO posPadre);
	void intercambiar(TIPO_DATO posRama,TIPO_DATO posRamaHrno,TIPO_DATO posPadre);
	bool fusionIzquierda();
	void fusion();
	bool equilibrarDerecho();
	void intercambiarDerecho();
	bool equilibrarIzquierdo();
	TIPO_DATO getCantBloque(){return m_cantBloques;}	
	void escribirDisco();
	void inicializoRama();
	void OrdenarBloques();
	void limpiar();
	void insertarVectorSec(CClave clave);
	bool puedoFusionar(TIPO_DATO posRama,TIPO_DATO posRamaHrno,TIPO_DATO posPadre);
public:
	CArbolB(string nombre);
	CArbolB();
	~CArbolB();
	
	bool buscar(CClave& clave, TIPO_DATO& bloque);
	void abrirArchivo(void);
	void cerrarArchivo(void);
	void cargarBuffer(TIPO_DATO bloque);
	void cargarBufferSet(TIPO_DATO bloque);
	bool encontroClaveEnBuff(CClave& clave, TIPO_DATO &sigBloque);
	bool insertar(CClave& clave);
	bool insertaRecursivo(CClave& clave, TIPO_DATO posRama,TIPO_DATO izq, TIPO_DATO der);
	void distribuirClaves( TIPO_DATO posNodoViejo, TIPO_DATO posNodoNuevo,CClave &clave );
	TIPO_DATO eliminar(CClave& clave);
	void mostrarRama();
	bool ramaEsVacia(){return (m_posRama == 0);};
	CClave &getClaveAux(){return m_claveAux;}
	fstream &getArchivo(){return m_archivoListaSec;}
	void leerBloque(TIPO_DATO nroBloque);
	bool cambiarClave(CClave &claveVieja,CClave &claveNueva);
	TIPO_DATO getSiguiente(){return m_siguiente;}
	void leerClaveDeBloque(TIPO_DATO nroBloque ,CClave &claveAux);
	void buscarPrimeraHoja(TIPO_DATO &nroBloque);
//	void exportarSet(string nombreArch, fstream archDato);
	void getVectorClavesSet(TIPO_DATO &blqSig, vector<void*> *unVector);
	bool obtenerNroBloque(CClave &espacioLibre,TIPO_DATO &nroBloqueOut);
	bool eliminarElemVector(CClave &claveIn);
	bool getEncontro(){return m_encontro;}
	TIPO_DATO getPosRamaAux(){return m_posRamaAux;}
	
	void incCosto(void){this->m_costoProceso++;} //(CTO_PROC)
	void inicializarCosto(void){this->m_costoProceso = 0;}
	int getCosto(void){return this->m_costoProceso;}
	
	
};
/*-----------------------------------------------------------*/
/** Constructor*/
template <class CClave>
CArbolB<CClave>::CArbolB()
{
}
template <class CClave>
CArbolB<CClave>::CArbolB(string nombre):m_archIndice(nombre)
{
	recursivo=0;
//	this->abrirArchivo();
	m_posRama=0;
	m_posRamaAux=0;
	m_posModificado = 0 ;
	//m_rama.clear();
	m_hrnoDerecho = false;
	m_cantBloques = m_archIndice.cantBloques();
	m_archivoListaSec.open(((string)"Lista"+nombre).c_str(),ios::in | ios::out | ios::binary | ios::trunc);
	m_tamanioArchivo = 0;
}

/** Destructor*/
template <class CClave >
CArbolB<CClave>::~CArbolB()
{
	if(m_archivoListaSec.is_open())
		m_archivoListaSec.close();
	if(m_archIndice.is_open())
		m_archIndice.cerrar();	
	else
		cout<<"El archivo se quizo cerrar y no estaba abierto."<<endl;
}
/*-----------------------------------------------------------*/
/** Busca la clave que recibe por parametros y devuelve el bloque
 *  donde se encuentra la clave o donde deberia estar la clave
 *  si es que llego a una hoja y no lo encontro.*/
template <class CClave >
bool CArbolB<CClave>::buscar(CClave& clave, TIPO_DATO& bloque)
{
	//inicializo la variable con el maximo valor posible
	TIPO_DATO blqSigBusqueda=0; //contiene el valor de retorno
	bool encontrado = false;
	++this->recursivo;
	if(this->recursivo==40)
		cout<<"Es demasiado!!!"<<endl;
	//lee el bloque cuyo nro recibe por parametro y lo carga en el buff
	this->cargarBuffer(bloque);	
	if(((CNodoBase<CClave>*)m_rama[m_posRama-1])->getCantRegistros()!=0) //si el archivo esta vacio no busca	
	//recorro el buff buscando la clave
	//si la encuentra, termina. Sino hay que ver si llama recursivamente o llego a una hoja
/*B+	if(!(encontrado = this->encontroClaveEnBuff(clave,blqSigBusqueda)))//si no es hoja recursion, si es hoja retorna bloque aproximado
		if( !((CNodoBase<CClave>*)m_rama[m_posRama-1])->esHoja() )
			encontrado = buscar(clave,blqSigBusqueda); //llamada recursiva con el bloque hijo correspondiente
ESTA REESCRITO ABAJO*/

	//B+ Si no es hoja debo seguir buscando para armar la rama completa
	{ //B++
		encontrado = this->encontroClaveEnBuff(clave,blqSigBusqueda); 
		if( !((CNodoBase<CClave>*)m_rama[m_posRama-1])->esHoja() ) 
			encontrado = buscar(clave,blqSigBusqueda);
	} //b++
	//en este punto, la variable blqResultado contiene el valor a retornar
	return encontrado;		
}
/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::limpiar()
{
	itMapNodo it;
/*
	for(it = this->m_rama.begin();it != this->m_rama.end();it++)
	{
		delete((CNodoBase<CClave>*)((*it).second));
		//m_rama.erase(it);
	}	
*/
	m_rama.clear();
}
template <class CClave >
void CArbolB<CClave>::inicializoRama()
{
	m_rama[m_posRama++]= new CHoja<CClave>;
}
/*-----------------------------------------------------------*/
/**Lee el bloque cuyo nro recibe por parametro y se lo asigna al 
 * buffer del arbol.*/
template <class CClave >
void CArbolB<CClave>::cargarBuffer(TIPO_DATO bloque)
{
	TIPO_DATO tamanio = 0;
	bool esNoHoja;
	
	this->incCosto(); //incremento el costo de procesamiento (CTO_PROC)
		
	if (bloque == 51)
		cout<<"Lo encontre"<<endl;
	//veo el tamanio del archivo para saber si lo primero que leo (raiz)
	//la guardo en un nodo o en una hoja
	if (bloque == 0)//quiero levantar la raiz
	{	
		//this->m_rama.clear();	//inicializo la rama
		limpiar();
		m_posRama = 0;
		//obtengo el tamanio del archivo
		tamanio = m_archIndice.getTamanio();
		if(tamanio==0)
		{
			inicializoRama();
			return;
		}
		//si el arch tiene mas de un nodo el primero es NODO, sino es HOJA
		if( tamanio > TAMANIO_NODO && m_tamanioArchivo!=0) 
			//es NODO
			esNoHoja = true;
		else
			//es HOJA
			esNoHoja = false;			
	}
	else//veo en que nivel esta para saber si es hoja o no
	{
		if ( ((CNodoBase<CClave>*)m_rama[m_posRama-1])->sigueHoja() )
			//es HOJA
			esNoHoja = false;						
		else
			//es NODO
			esNoHoja = true;			
	}
	//cargo el bloque en el nodo que corresponda
	if(esNoHoja)
	{
		m_rama[m_posRama++]= new CNodo<CClave>;
		
	//((CNodo*)nodo) casteo de un puntero CNodoBase a un puntero CNodo
	//*((CNodo*)nodo) le estoy pasando el objeto CNodo para que el metodo lo obtenga por referencia
		this->m_archIndice.read(*((CNodo<CClave>*)m_rama[m_posRama-1]),bloque);
	}
	else
	{
		m_rama[m_posRama++]= new CHoja<CClave>;
		if(!this->m_archIndice.is_open())
			cout<<"Archivo no esta abierto"<<endl;

		this->m_archIndice.read(*((CHoja<CClave>*)m_rama[m_posRama-1]),bloque);
		
	}
}

/*-----------------------------------------------------------*/
/**Lee el bloque cuyo nro recibe por parametro y se lo asigna al 
 * buffer del arbol.*/
template <class CClave >
void CArbolB<CClave>::cargarBufferSet(TIPO_DATO bloque)
{
	if(bloque == 0)
		return;
		
	//En el set secuencial solo hay hojas
	m_rama[m_posRama++]= new CHoja<CClave>;	
	this->m_archIndice.read(*((CHoja<CClave>*)m_rama[m_posRama-1]),bloque);	
}

/*-----------------------------------------------------------*/
/**Recorre el buff buscando la clave, si la encuentra retorna true
 * indicando que el bloque actual contiene esa clave. Sino actualiza
 * el siguiente bloque que se debe buscar y retorna false.
 * sigBloque: 	indicara el nro de bloque que se debera procesar posteriormente
 * 				en caso que el metodo retorne false.*/
template <class CClave>
bool CArbolB<CClave>::encontroClaveEnBuff(CClave& clave, TIPO_DATO &sigBloque)
{
	TIPO_DATO i=0, cantReg;
	CClave claveAux;
/**/claveAux = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(i);
	cantReg = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getCantRegistros();

	//recorre el vector de claves ordenado, hasta llegar al final o encontrar una clave mayor
/*	while(  (i < ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getCantRegistros()) && 
		(((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(i)< clave)  )
*/	
	while( (i < cantReg) && 
			((claveAux = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(i))< clave)  )
	{		
//		claveAux = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(i);
//	cantReg = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getCantRegistros();
		++i;		
	}

	//salio sin llegar al final
/*	if(i < ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getCantRegistros())
*/	
	if(i < cantReg) //salio sin llegar al final
	{
		claveAux = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(i);
		if(clave == claveAux)
		{	
			((CNodoBase<CClave>*)m_rama[m_posRama-1])->setPosicion(i);
			//m_claveAux=clave;
			if( ((CNodoBase<CClave>*)m_rama[m_posRama-1])->esHoja() )/*B+*/
			{
				clave = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(i);
				this->m_claveAux = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(i);
				return true;
			}
			else 
			{	/*B+ SI ES HOJA???*/
				sigBloque = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorDer(i);
//				if(i==0)
//					sigBloque = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorIzq();
//				else
//					sigBloque = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorDer(i-1);
				return false;
			}
		}
		
		//la clave que busco es menor a la que esta en la pos i 
		if ( !((CNodoBase<CClave>*)m_rama[m_posRama-1])->esHoja() )//si tiene un sucesor
		{
			if(i==0)//el primer valor es mayor a la clave que busco
				sigBloque = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorIzq();			
			else
			{
				sigBloque = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorDer(i-1);
				--i;
			}
		}else//este es el caso en que no se encontro la clave y es hoja			
			{
					this->m_claveAux = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(i);		
					this->m_posRamaAux = m_posRama-1;
			}
				((CNodoBase<CClave>*)m_rama[m_posRama-1])->setPosicion(i);
	}	
	else //no hay elementos mayores en el buff
	{
		if ( !((CNodoBase<CClave>*)m_rama[m_posRama-1])->esHoja() )//si tiene un sucesor	
			{				
				sigBloque = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorDer(i-1); //VER si el ultimo elemento es i o (i-1)
				((CNodoBase<CClave>*)m_rama[m_posRama-1])->setPosicion(i-1);
				this->m_posRamaAux = m_posRama-1;
				
			}
		else//entramos aca si se llego al final del nodo y no se encontro la clave
		{
			//m_siguiente=((CNodoBase<CClave>*)m_rama[m_posRama-1])->getSigSetSec();
			
			//TIPO_DATO siguiente;			
			if((m_siguiente=((CNodoBase<CClave>*)m_rama[m_posRama-1])->getSigSetSec())==0)
				m_claveAux= ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(((CNodoBase<CClave>*)m_rama[m_posRama-1])->getCantRegistros()-1);
			else
				//este es el caso en que no lo encontro pero tiene una hoja hermana siguiente
			{
				if(!((CNodoBase<CClave>*)m_rama[m_posRama-1])->esRaiz())
				{
					TIPO_DATO sucIzqPadre,nroBloqueHijo;
					//obtengo el sucesor Izq del padre
					sucIzqPadre = ((CNodoBase<CClave>*)m_rama[m_posRama-2])->getSucesorIzq();
					nroBloqueHijo = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getNroBloque();
					if(sucIzqPadre != nroBloqueHijo)
						((CNodoBase<CClave>*)m_rama[m_posRama-2])->setPosicion(((CNodoBase<CClave>*)m_rama[m_posRama-2])->getPosicion()+1);
	
	//							m_rama[m_posRama++]=new CHoja<CClave>;
	//			m_archIndice.read(*((CHoja<CClave>*)m_rama[m_posRama-1]),nroBloqueSiguiente);		
	
					m_rama[m_posRama++]= new CHoja<CClave>;
	
					this->m_archIndice.read(*((CHoja<CClave>*)m_rama[m_posRama-1]),m_siguiente);
					this->m_claveAux = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(0);		
					this->m_posRamaAux = m_posRama-1;
					if(m_claveAux  == clave)
						cout<<"No tendria que entrar aca!!!"<<endl;
						//return true;
				}
			}
			
				//m_siguiente = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getNroBloque();
		/*	{
				//es para la busqueda cuando no encuentra el siguiente.
			//	m_rama[m_posRama++]= new CHoja<CClave>;
			//	this->m_archIndice.read(*((CHoja<CClave>*)m_rama[m_posRama-1]),siguiente);
				m_claveAux= ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(0);
			}
			else
				m_claveAux= ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(((CNodoBase<CClave>*)m_rama[m_posRama-1])->getCantRegistros()-1);
				*/
			/*
			if(!((CNodoBase<CClave>*)m_rama[m_posRama-1])->esRaiz())
			{
				TIPO_DATO posPadre;
				posPadre = ((CNodo<CClave>*)m_rama[m_posRama-2])->getPosicion();
				if((posPadre+1) < ((CNodo<CClave>*)m_rama[m_posRama-2])->getCantRegistros())
				//devuelvo al hermano del padre					
					m_claveAux= ((CNodoBase<CClave>*)m_rama[m_posRama-2])->getClave(posPadre+1);			
				
				else// el padre no tiene hermano mayor.
				{					
					m_claveAux= ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(i-1);
					cout<<"No hay un registro inmediatamente mayor."<<endl;
				}
			}
			else//porque el nodo es raiz y no tiene mas elementos
			{				
				m_claveAux= ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(i-1);
				cout<<"No hay un registro inmediatamente mayor y es Raiz"<<endl;				
			}
			*/
		}	
	//	--i; //si (i==cantReg) => la posicion real de la ultima clave del nodo es (i-1)
	}
/*		if ( !((CNodoBase<CClave>*)m_rama[m_posRama-1])->esHoja() )//si tiene un sucesor					
			sigBloque = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorDer(i-1); //VER si el ultimo elemento es i o (i-1)	
		else		
			--i;
*/
	// ((CNodoBase<CClave>*)m_rama[m_posRama-1])->setPosicion(i);
	return false; 
}
template <class CClave>
void CArbolB<CClave>::insertarVectorSec(CClave clave)
{
	//((CNodoBase<CClave>*)m_rama[m_posRama-1])->insertarVectorSec(clave,m_archivoListaSec)
}
/*-----------------------------------------------------------*/
template <class CClave>
bool CArbolB<CClave>::insertar(CClave& clave)
{
    TIPO_DATO  bloqueRaiz=0;
	m_posModificado = 0 ;     
	//if(m_archIndice.getTamanio()==0)
		//el archivo esta vacio
	this->recursivo=0;
	//clave.mostrar();
	this->m_claveIn = clave;
	//this->m_claveIn.mostrar();
    if( this->buscar(clave,bloqueRaiz) ) //el buscar arma la rama 
    {

		this->m_claveIn.mostrar();
		((CNodoBase<CClave>*)m_rama[m_posRama-1])->insertarVectorSec(m_claveIn,m_archivoListaSec);
		if(((CNodoBase<CClave>*)m_rama[m_posRama-1])->getNivel()==0)
			m_archIndice.write(((CHoja<CClave>*)m_rama[m_posRama-1]));
		else
			m_archIndice.write(((CNodo<CClave>*)m_rama[m_posRama-1]));
		((CNodoBase<CClave>*)m_rama[m_posRama-1])->mostrar();
//        cout<<"La clave ya se encuentra en el archivo."<<endl;    
        return false;
    }
	/*puede ser que haya leido el siguiente mas proximo en el buscar, para sacar las dos hojas consecutivas 
	 * que se crearon borro la ultima*/
	if(!((CNodoBase<CClave>*)m_rama[m_posRama -1])->esRaiz() &&((CNodoBase<CClave>*)m_rama[m_posRama -2])->esHoja())
	{		
		m_rama.erase(m_posRama-1);
		m_posRama--;
	}

    //Si pasa esta linea es porque DEBE insertar el dato
    if( !insertaRecursivo(clave,m_posRama-1,TIPO_DATO_MAX,TIPO_DATO_MAX) )
    {
        cout<<"Problemas con el insertar recursivo."<<endl;    
        return false;        
    }
//    cout<<"La clave ya se inserto correctamente en el archivo."<<endl;    
    //me fijo donde quedo la posicion dentro de la rama, para saber 
    //hasta donde se modifico
	escribirDisco(); //hago el indice consistente
	//m_archIndice.write(
    return true;
}
/*-----------------------------------------------------------*/
template <class CClave>
void CArbolB<CClave>::escribirDisco()
{
	TIPO_DATO i=0;	
	//OrdenarBloques();
	while(i<m_posRama)
	{
		if(((CNodoBase<CClave>*)m_rama[i])->getNivel()==0)
			m_archIndice.write(((CHoja<CClave>*)m_rama[i]));
		else
			m_archIndice.write(((CNodo<CClave>*)m_rama[i]));
		i++;
		this->incCosto(); //(CTO_PROC)
	}
//	for(it = m_rama.begin();it != m_rama.end();it++)
//		m_archIndice.write(((void*)(*it)));
}
template <class CClave>
void CArbolB<CClave>::OrdenarBloques()
{
	itMapNodo	it;
	it=m_rama.begin();	
}
/*-----------------------------------------------------------*/
template <class CClave>
bool CArbolB<CClave>::insertaRecursivo(CClave& clave, TIPO_DATO posRama, TIPO_DATO izq, TIPO_DATO der)
{
	int nivel;
	nivel = ((CNodoBase<CClave>*)m_rama[posRama])->getNivel();
	if ( !(((CNodoBase<CClave>*)m_rama[posRama])->hayLugar(clave)) )
	{    
		if( ((CNodoBase<CClave>*)m_rama[posRama])->getNroBloque() == 665)
			cout<<"Lo encontre"<<endl;
		
		if(izq==0 || der==0)
			cout<<"NO deveria pasar !!!!!!!!!"<<endl;
		/* crear nodo nuevo y lo coloca al final de la rama
		* TODO inicializar los atributos del nuevo nodo de forma correcta
		*/
		if(((CNodoBase<CClave>*)m_rama[posRama])->esHoja())
		{
			m_rama[m_posRama++] = new CHoja<CClave>(nivel,++m_cantBloques);
			//Acutalizo los sig de las dos hojas 			
			((CHoja<CClave>*)m_rama[m_posRama-1])->setSigSetSec(((CHoja<CClave>*)m_rama[posRama])->getSigSetSec());//El siguiente de la nueva hoja es el siguiente de la hoja anterior/*B+*/   
			((CHoja<CClave>*)m_rama[posRama])->setSigSetSec(m_cantBloques); //Actualizo la conexion en el set secuencial /*B+*/

			((CHoja<CClave>*)m_rama[posRama])->distribuirClaves(izq,der,clave,*((CHoja<CClave>*)m_rama[m_posRama-1]));
			mostrarRama();
		}
		else 
		{
			m_rama[m_posRama++]= new CNodo<CClave>(nivel,++m_cantBloques);
			((CNodo<CClave>*)m_rama[posRama])->distribuirClaves(izq ,der,clave,*((CNodo<CClave>*)m_rama[m_posRama-1]));        		       		
		}
		if((izq==0 || der==0) && posRama!=0 )
			cout<<"NO deveria pasar !!!!!!!!!"<<endl;

		/* Metodo que redistribuye las claves entre los nodos viejo y nuevo
		* usando un supernodo auxiliar.
		* retornando el valor de la clave que debe ser promovida al padre
		*/
	   if( posRama==0 )
	   {	//debo crear una raiz al arbol que sera el primer elemento de la rama
			//Si se debe crear una nueva raiz => creo un nuevo nodo, que sera la raiz, 
			//le asigno la clave que se le promueve y le actualizo sus atributos
			/*VER SI ESTE NUEVO NODO TIENE QUE IR AL COMIENZO DE LA RAMA O NO HACE FALTA*/
	//		nroBloqueNuevo = ++m_cantBloques; //Sera un nodo nuevo, es un bloque nuevo, es la raiz
			m_rama[m_posRama++]= new CNodo<CClave>(nivel+1,++m_cantBloques);			
			if( ((CNodoBase<CClave>*)m_rama[posRama])->getNroBloque() == 665) cout<<"Lo encontre"<<endl;
			//A la antigua raiz le intercambio el nro de bloque con el del nodo que recien cree
			//Le inserto la clave al nodo que recien cree y le actualizo sus sucesores.			
			((CNodo<CClave>*)m_rama[m_posRama-1])->redistribuirRaiz(clave, izq, der,*((CNodoBase<CClave>*)m_rama[posRama]));   							
			((CNodo<CClave>*)m_rama[m_posRama-2])->setSigSetSec(0);
			/*TODO VER SI se debe intercambiar los nodos de la rama primero y ultimo
			 * La rama debe tener los nodos ordenados, VER EL ESCRIBIR DISCO*/
			cout<<"Muestro rama luego de crear e insertar en nueva raiz"<<endl;
			mostrarRama();
			m_tamanioArchivo = 1; //esto lo puedo mejorar.			
			return true;
	   }
	   else
	   		this->insertaRecursivo(clave, --posRama, izq, der);            
	}
	 else //el nodo actual tiene lugar para esta clave
	 {
	 	if( ((CNodoBase<CClave>*)m_rama[posRama])->getNroBloque() == 666)
			cout<<"Lo encontre, el nodo actual tiene lugar para esta clave."<<endl;

		if(izq==0 || der==0)
			cout<<"NO deveria pasar !!!!!!!!!"<<endl;	 		

		((CNodoBase<CClave>*)m_rama[posRama])->insertarOrdenado(clave,izq, der);
		//voy a actualizar el padre de la hoja
//		if( (((CNodoBase<CClave>*)m_rama[posRama])->getPosicion() == 0) && !((CNodoBase<CClave>*)m_rama[posRama])->esRaiz()/*B++*/ && ((CNodoBase<CClave>*)m_rama[posRama])->esHoja())
//		{
/*B+++*///	((CNodoBase<CClave>*)m_rama[posRama-1])->setClave(clave,((CNodoBase<CClave>*)m_rama[posRama-1])->getPosicion()/*+1*/); //B++ Si se inserta en la primer pos el padre no deberia haberlo mandado a la hoja de la izq. SOLO DEBE ACTUALIZAR CUANDO SE HACE SPLIT???!!!!!
		//}
		cout<<"Muestro rama en el insertar recursivo cuando hubo lugar"<<endl;
		mostrarRama();		
	 }

//	cout<<"Muestro rama en el insertar recursivo cuando hubo lugar"<<endl;
//	mostrarRama();
	return true;     
}
/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::mostrarRama()
{
	TIPO_DATO i=0,cantElemRama=0;
	TIPO_DATO nivel;
	CClave claveAux;
	
	cantElemRama = (TIPO_DATO)m_rama.size();
	do{
		nivel = ((CNodoBase<CClave>*)m_rama[i])->getNivel();
		cout<<"Nivel ::: "<<nivel<<endl;
		if(nivel==0)		
			((CHoja<CClave>*)m_rama[i])->mostrar();
		else
			((CNodo<CClave>*)m_rama[i])->mostrar();
		i++;
//	}while(i<=nivel);
	}while(i<cantElemRama);

}
/*-----------------------------------------------------------*/
template <class CClave>
bool CArbolB<CClave>::insertarClave(CClave& clave)
{
	TIPO_DATO tamClave=0,tamEspacioLibre=0;
	tamClave= clave.getTamanio();
	tamEspacioLibre = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getEspacioLibre();
	if(tamClave <=tamEspacioLibre )
	{
		
		((CNodoBase<CClave>*)m_rama[m_posRama-1])->insertarOrdenado(clave);
		//Actualizo el espacio libre del nodo
		((CNodoBase<CClave>*)m_rama[m_posRama-1])->setEspacio(tamClave + tamEspacioLibre);
		return true;
	}
	//Si hay overflow
	return false;
}
//*-----------------------------------------------------------*/
/*con este metodo piemso borrar dentro del nodo la clave que se pasa por parametro
 * si la puede borrar devuelve la referencia que tiene la clave primaria que estoy
 * borrando. para terminar de hacer el borrado dentro del archivo de datos*/
template <class CClave >
TIPO_DATO CArbolB<CClave>::eliminar(CClave& clave)
{
	TIPO_DATO posRaiz=0,posicion;
	if (!buscar(clave,posRaiz))
	{
		cout<<"El elemento que quiere borrar no se encontro."<<endl;
	 	return 0;
	}
	/*no necesito dos hojas en el final*/
	if(!((CNodoBase<CClave>*)m_rama[m_posRama -1])->esRaiz() && ((CNodoBase<CClave>*)m_rama[m_posRama -2])->esHoja())
	{
		m_rama.erase(m_posRama -1);
		m_posRama--;
	}	
	this->m_claveAux = clave;
	//intercambioClaves(clave);
	posicion = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getPosicion();
	((CNodoBase<CClave>*)m_rama[m_posRama-1])->eliminar(posicion);
	//se supone que alterminar este metodo se borro la clave promovida de la hoja
	//si es raiz y esta vacia tengo que bajar el nivel
	this->resolverUnderflow(m_posRama-1);
	clave =this->m_claveAux ;
	//mostrarRama();
	escribirDisco();
	return 1;
}
/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::intercambioClaves(CClave& clave)
{
	int indice=0,nivel;
	TIPO_DATO indiceAux;
	
	TIPO_DATO nroBloqueSiguiente; //es el numero de bloque que se va a leer de disco
	CClave claveAux1,claveAux2;
	TIPO_DATO posRamaBorrado= m_posRama-1;
	indice = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getPosicion();	
	nivel = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getNivel();
	indiceAux = indice ;
	if(nivel>0)
	{//cargo el bloque derecho
		if(nivel==1)
		{
			nroBloqueSiguiente = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorDer(indice);
			m_rama[m_posRama++]=new CHoja<CClave>;
			m_archIndice.read(*((CHoja<CClave>*)m_rama[m_posRama-1]),nroBloqueSiguiente);		
			--nivel;		
			
		}
		else
		{
			nroBloqueSiguiente = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorDer(indice);
			m_rama[m_posRama++]=new CNodo<CClave>;
			m_archIndice.read(*((CNodo<CClave>*)m_rama[m_posRama-1]),nroBloqueSiguiente);		
			--nivel;	
		}
		while(nivel>1)
		{//cargo los buffer izquierdos			
			
			nroBloqueSiguiente = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorIzq();
			m_rama[m_posRama++]=new CNodo<CClave>;
			m_archIndice.read(*((CNodo<CClave>*)m_rama[m_posRama-1]),nroBloqueSiguiente);
			--nivel;		
		}
		if(nivel==1)
		{
			nroBloqueSiguiente = ((CNodo<CClave>*)m_rama[m_posRama-1])->getSucesorIzq();
			m_rama[m_posRama++]=new CHoja<CClave>;
			m_archIndice.read(*((CHoja<CClave>*)m_rama[m_posRama-1]),nroBloqueSiguiente);		
		}
		//intercambio entre las claves.
		claveAux1 = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getClave(0);
		claveAux2 = ((CNodoBase<CClave>*)m_rama[posRamaBorrado])->getClave(indice);
		((CNodoBase<CClave>*)m_rama[m_posRama-1])->setClave(claveAux2,0);
		((CNodoBase<CClave>*)m_rama[m_posRama-1])->setPosicion(0);
		((CNodoBase<CClave>*)m_rama[posRamaBorrado])->setClave(claveAux1,indice);		
	}
}

/*-----------------------------------------------------------*/
template <class CClave >
bool CArbolB<CClave>::puedoFusionar(TIPO_DATO posRama,TIPO_DATO posRamaHrno,TIPO_DATO posPadre)
{
	TIPO_DATO tamFusionado,tamHermano,tamClave;

	tamFusionado = ((CNodoBase<CClave>*)m_rama[posRama])->getTamanio();
	tamHermano = ((CNodoBase<CClave>*)m_rama[posRamaHrno])->getTamanio();
	/*se puede usar "-1" porque cuando uso este metodo entra si no es la raiz*/
	tamClave =((CNodoBase<CClave>*)m_rama[posRama -1])->getTamanio(posPadre);
//	if(( tamFusionado + tamHermano + tamClave )<=TAMANIO_NODO)
	if(((CNodoBase<CClave>*)m_rama[posRama])->puedoFusionar(tamHermano,tamClave))
		return true;
	return false;
}
/*-----------------------------------------------------------*/

template <class CClave >
TIPO_DATO CArbolB<CClave>::resolverUnderflow(TIPO_DATO posRama)
{
	TIPO_DATO posRamaHrno,posPadre;
	if(!((CNodoBase<CClave>*)m_rama[posRama ])->esRaiz()&&
	 (((CNodoBase<CClave>*)m_rama[posRama])->esUnderflow()))
	{	
		//pregunto si el vecino izquierdo tiene lugar para pasarle el registro que necesita 
		// el nodo que se esta borrando
		//Ademas verifica que al sacar al clave no quede en underflow
		if(hrnoConElemento(posRama,posRamaHrno,posPadre) )//&& ((CNodoBase<CClave>*)m_rama[posRama])->esHoja())
		{
			intercambiar(posRama,posRamaHrno,posPadre);
			m_tamanioArchivo = 1; //esto lo puedo mejorar.						
			return 1;//verque devuelvo
		}
		/*en este punto puede ser que al fusionarse dos nodos, pueda quedar en underflow 
		 * el nodo padre, este tambien tiene que tratarse de la misma manera hasta que se 
		 * trate del nodo raiz*/
		else//pregunto si puedo hacer fusion con el vecino
//			if(hrnoParaFusionar(posRama,posRamaHrno,posPadre))
			{
			/*si estoy borrando un nodo que esta en la parte izquierda no tendria
			 *  que poder fusionar con el vecion izquierdo porque no existe.*/
				if(puedoFusionar(posRama,posRamaHrno,posPadre))
				{
				 	fusionar(posRama,posRamaHrno,posPadre);
				 	resolverUnderflow(posRama);
				}
			}
		
	}
	else
	{	//cuando todo se fusiono, y la raiz no tendria que existir mas los dos hermanos que se unieron se convierten en la nueva raiz
		if(((CNodoBase<CClave>*)m_rama[posRama ])->esRaiz() && ((CNodoBase<CClave>*)m_rama[posRama ])->getCantRegistros()==0)	
		{
			if(m_rama.size()>1)
			{
				((CNodoBase<CClave>*)m_rama[posRama])->setNroBloque(((CNodoBase<CClave>*)m_rama[posRama + 1])->getNroBloque());
				((CNodoBase<CClave>*)m_rama[posRama + 1])->setNroBloque(0);	//es la nueva raiz
				if(((CNodoBase<CClave>*)m_rama[posRama + 1])->getNivel()==0)
					m_tamanioArchivo=0; //esto tendria que mejorarlo, porahora queda asi.
			}
		}
	}
	
	return 0;
}
/*-----------------------------------------------------------*/
/*VERRRRRRRRRRRRR QUE PASA CON  LAS POSICIONES DE LA RAMA !!!!!!!!!!!!!!!!!!!!!!*/
template <class CClave >
bool CArbolB<CClave>::hrnoConElemento(TIPO_DATO posRama,TIPO_DATO &posRamaHrno,TIPO_DATO &posPadre)
{
	TIPO_DATO /*posPadre,*/posHijo;//posicion de la clave dentro del vector.
	TIPO_DATO hrnoDerecho,bloqueHijo,hrnoIzquierdo;
	TIPO_DATO cantReg;//cantidad de registros del vector de claves

	//elimino al hermano donde no fue encontrado el dato
	if(((CNodoBase<CClave>*)m_rama[posRama -1])->esHoja())
	{		
		m_rama.erase(posRama-1);
		m_posRama--;
	}

	posPadre = ((CNodoBase<CClave>*)m_rama[posRama -1])->getPosicion();
	hrnoDerecho = ((CNodo<CClave>*)m_rama[posRama -1])->getSucesorDer(posPadre);
	cantReg = ((CNodo<CClave>*)m_rama[posRama -1])->getCantRegistros();

	posHijo = ((CNodoBase<CClave>*)m_rama[posRama -0])->getPosicion();
	//bloqueHijo = ((CNodo<CClave>*)m_rama)[posRama -1]->getSucesorDer(posHijo);
	bloqueHijo = ((CNodo<CClave>*)m_rama[posRama -0])->getNroBloque();

		//ubico el hermano derecho
	if((posPadre< (cantReg-1))|| hrnoDerecho!=bloqueHijo )
   {
	   	if(posPadre< (cantReg-1) && hrnoDerecho==bloqueHijo)
			hrnoDerecho = ((CNodo<CClave>*)m_rama[posRama -1])->getSucesorDer(posPadre+1);
		
		if(((CNodoBase<CClave>*)m_rama[posRama -1])->getSucesorIzq()!= bloqueHijo)
			++posPadre;  //incremento cuando no comparte el padre con el hrno derecho
		((CNodo<CClave>*)m_rama[posRama -1])->setPosicion(posPadre);

		if(((CNodoBase<CClave>*)m_rama[posRama -0])->esHoja())	
		{
			m_rama[m_posRama++] = new CHoja<CClave>;
			m_archIndice.read(*((CHoja<CClave>*)m_rama[m_posRama-1]),hrnoDerecho);
		}
		else	
		{
			m_rama[m_posRama++] = new CNodo<CClave>;
			m_archIndice.read(*((CNodo<CClave>*)m_rama[m_posRama-1]),hrnoDerecho);
		}
		
		posRamaHrno = m_posRama-1;

		//con el nuevo hermano leido verifico si tiene un registro para entregar sin quedar en underflow
		if(((CNodoBase<CClave>*)m_rama[m_posRama-1])->equilibrarConHrno(0))
		{
			m_hrnoDerecho = true;
			//si el hermano puede ceder un registro sale con true
			return true;
		}

	}
	else
	{
		/** si no encontro lugar en el hrno derecho me fijo en el hrno izquierdo*/
		if(posPadre==0)
			hrnoIzquierdo = ((CNodo<CClave>*)m_rama[posRama -1])->getSucesorIzq();	
		else
		{
			hrnoIzquierdo = ((CNodo<CClave>*)m_rama[posRama -1])->getSucesorDer(posPadre-1);
		}
		//busco en el hrno izquierdo
		if(bloqueHijo != hrnoIzquierdo )
		{
			TIPO_DATO cantRegistros;
			if(posPadre!=0)
				hrnoIzquierdo = ((CNodo<CClave>*)m_rama[posRama -1])->getSucesorDer(posPadre-1);
			if(((CNodoBase<CClave>*)m_rama[posRama -0])->esHoja())	
			{
				m_rama[m_posRama++] = new CHoja<CClave>;
				m_archIndice.read(*((CHoja<CClave>*)m_rama[m_posRama-1]),hrnoIzquierdo);
			}
			else	
			{
				m_rama[m_posRama++] = new CNodo<CClave>;
				m_archIndice.read(*((CNodo<CClave>*)m_rama[m_posRama-1]),hrnoIzquierdo);
			}
			
			cantRegistros = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getCantRegistros();
			//--posPadre;  
			posRamaHrno = m_posRama-1;

			//con el nuevo hermano leido verifico si tiene un registro para entregar sin quedar en underflow
			if(((CNodoBase<CClave>*)m_rama[m_posRama-1])->equilibrarConHrno(cantRegistros-1))
			{
				m_hrnoDerecho = false;
				//si el hermano puede ceder un registro sale con true
				return true;		
			}
		}
	}
	return false;
}
/*-----------------------------------------------------------*/
/*cuando entro aca se que se puede intercambiar un registro con un hermano, es mas, 
 * yo se que ese hermano esta al final de la rama*/
template <class CClave >
void CArbolB<CClave>::intercambiar(TIPO_DATO posRama,TIPO_DATO posRamaHrno,TIPO_DATO posPadre)
{
	((CNodoBase<CClave>*)m_rama[posRama])->intercambiar(*((CNodoBase<CClave>*)m_rama[posRamaHrno]),m_hrnoDerecho,*((CNodoBase<CClave>*)m_rama[posRama-1]),posPadre);

/*
	CClave *spClaveHrno=NULL;
	TIPO_DATO pos,cantRegistros,sucDerHrno,indice;
	spClaveHrno = new CClave;
	//spClavePadre =new CClave;
	//ESTE IF ESTA MAL VER COMO DIFERENCIO SI AGARRO EL HRNO DERECHO O EL IZQUIERDO
//	

	if(m_hrnoDerecho)//el hrno que le va a prestar es el derecho
		indice = 0;
	else
		indice = cantRegistros = ((CNodoBase<CClave>*)m_rama[posRamaHrno])->getCantRegistros() -1;

	//obtengo la clave del hermano
	spClaveHrno =((CNodoBase<CClave>*)m_rama[posRamaHrno])->getspClave(indice);
	sucDerHrno = ((CNodoBase<CClave>*)m_rama[posRamaHrno])->getSucesorDer(indice);
	((CNodoBase<CClave>*)m_rama[posRamaHrno])->eliminar(indice);	
	
//	cantRegistros = ((CNodoBase<CClave>*)m_rama[posRama-1])->getCantRegistros();
	//(*spClavePadre) = ((CNodoBase<CClave>*)m_rama[posRama-1])->getClave(posPadre);

	cantRegistros = ((CNodoBase<CClave>*)m_rama[posRama-0])->getCantRegistros();
	((CNodoBase<CClave>*)m_rama[posRama-0])->setCantRegistros(cantRegistros +1);
	pos = ((CNodoBase<CClave>*)m_rama[posRama -0])->getPosicion();		
	((CNodoBase<CClave>*)m_rama[posRama-0])->setClave(*spClaveHrno);	

	//en este caso se puede dar que se quiera fucionar con un padre que en una etapa previa se quedo sin elementos
	//pero tenia un hijo(por hacer una fusion) 
	
	if(!cantRegistros)
	{
		TIPO_DATO sucesorIzquierdo,sucesorDerecho;
		if(!m_hrnoDerecho)
		{
			sucesorIzquierdo = ((CNodoBase<CClave>*)m_rama[posRama-0])->getSucesorIzq() ;
			if( sucesorIzquierdo!=ULONG_MAX)
				((CNodoBase<CClave>*)m_rama[posRama-0])->setSucesorDer(sucesorIzquierdo,pos);
			((CNodoBase<CClave>*)m_rama[posRama-0])->setSucesorIzq(sucDerHrno);
				
		}
		else
		{
			sucesorDerecho = ((CNodoBase<CClave>*)m_rama[posRama-0])->getSucesorDer(pos);
			if(sucesorDerecho!=ULONG_MAX)
				((CNodoBase<CClave>*)m_rama[posRama-0])->setSucesorIzq(sucesorDerecho);
			((CNodoBase<CClave>*)m_rama[posRama-0])->setSucesorDer(sucDerHrno,pos);
			
		}
		((CNodoBase<CClave>*)m_rama[posRama-0])->setPosicion(pos);
	}
	
	((CNodoBase<CClave>*)m_rama[posRama-0])->ordenar();//despues de ordenar queda en la posicion=0 o al final
	//((CNodoBase<CClave>*)m_rama[posRama-0])->setPosicion(pos);
	((CNodoBase<CClave>*)m_rama[posRama-0])->mostrar();
	
	if(m_hrnoDerecho)
		spClaveHrno =((CNodoBase<CClave>*)m_rama[posRamaHrno])->getspClave(indice);
	((CNodoBase<CClave>*)m_rama[posRama-1])->setClave(*spClaveHrno,posPadre);

	//((CNodoBase<CClave>*)m_rama[posRama-0])->setSucesorDer(sucDerHrno,pos);
	*/
}
/*-----------------------------------------------------------*/
template <class CClave >
bool CArbolB<CClave>::hrnoParaFusionar(TIPO_DATO &posRama,TIPO_DATO &posRamaHrno,TIPO_DATO &posPadre)
{
	TIPO_DATO /*posPadre,*/posHijo;//posicion de la clave dentro del vector.
	TIPO_DATO hrnoDerecho,bloqueHijo,hrnoIzquierdo;
	TIPO_DATO cantReg;//cantidad de registros del vector de claves
	
	if(!((CNodoBase<CClave>*)m_rama[posRama -1])->esRaiz() && ((CNodoBase<CClave>*)m_rama[posRama -2])->esHoja())
	{
		m_rama[posRama -2] =m_rama[posRama -1];
		m_rama.erase(posRama -2);
		m_posRama--;
	}
	
	
	posPadre = ((CNodoBase<CClave>*)m_rama[posRama -2])->getPosicion();
	hrnoDerecho = ((CNodo<CClave>*)m_rama[posRama -2])->getSucesorDer(posPadre);
	cantReg = ((CNodo<CClave>*)m_rama[posRama -2])->getCantRegistros();

	posHijo = ((CNodoBase<CClave>*)m_rama[posRama -1])->getPosicion();
	//bloqueHijo = ((CNodo<CClave>*)m_rama)[posRama -1]->getSucesorDer(posHijo);
	bloqueHijo = ((CNodo<CClave>*)m_rama[posRama -1])->getNroBloque();
	
	
		//ubico el hermano derecho
	if((posPadre< (cantReg-1))|| hrnoDerecho!=bloqueHijo )
   {
	   	if(posPadre< (cantReg-1) && hrnoDerecho==bloqueHijo)
	   	{
			hrnoDerecho = ((CNodo<CClave>*)m_rama[posRama -2])->getSucesorDer(posPadre+1); 
			++posPadre;  
			posRamaHrno = posRama;
			m_hrnoDerecho = true;
			//si el hermano puede ceder un registro sale con true
			return true;
		}
	}
	/** si no encontro lugar en el hrno derecho me fijo en el hrno izquierdo*/
	hrnoIzquierdo = ((CNodo<CClave>*)m_rama[posRama -2])->getSucesorIzq();	
//	else
	//busco en el hrno izquierdo
	if(bloqueHijo != hrnoIzquierdo )
	{		
		if(posPadre!=0)
		{
			hrnoIzquierdo = ((CNodo<CClave>*)m_rama[posRama -2])->getSucesorDer(posPadre-1);
			--posPadre;  
			posRamaHrno = posRama;
			m_hrnoDerecho = false;
			//si el hermano puede ceder un registro sale con true
			return true;		
		}
	}
	return false;
}
/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::fusionar(TIPO_DATO &posRama,TIPO_DATO posRamaHrno,TIPO_DATO posPadre)
{
	((CNodoBase<CClave>*)m_rama[posRama])->fusionar(*((CNodoBase<CClave>*)m_rama[posRama-1])/*padre*/,posPadre,*((CNodoBase<CClave>*)m_rama[posRamaHrno])/*hermano*/);
	((CNodoBase<CClave>*)m_rama[posRama])->mostrar();
	posRama=posRama-1;
}
/*-----------------------------------------------------------*/
/*Pregunto si el vecino izquierdo me puede dar una clave para no estar en underflow*/
template <class CClave >
bool CArbolB<CClave>::equilibrarIzquierdo()
{
	/*TODO*///tendria que hacer un new
	if(((CNodoBase<CClave>*)m_rama)[m_posRama-1]->equilibrarConHrno())
		return true;
	return false;
}
/*-----------------------------------------------------------*/
template <class CClave >
bool CArbolB<CClave>::equilibrarDerecho()
{
	
	return false;
}
/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::intercambiarIzquierdo()
{
	
	return false;
}
/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::intercambiarDerecho()
{
	
	return false;
}
/*-----------------------------------------------------------*/
/* Visita hijo Izquierdo, luego el padre y finalmente el hijo Derecho*/
template <class CClave >
void CArbolB<CClave>::recorreEnOrden(TIPO_DATO &bloque)
{	
	TIPO_DATO posRama;
	
	//lee el bloque cuyo nro recibe por parametro y lo carga en el buff (rama)
	this->cargarBuffer(bloque);	
	posRama = m_posRama-1;
	if (((CNodoBase<CClave>*)m_rama)[posRama]->esHoja())
	{
		((CHoja<CClave>*)m_rama[posRama])->procesarHoja();
		podarRama(posRama);
	}
	else
	{		
		bloque = ((CNodo<CClave>*)m_rama)[posRama]->getSucesorIzq();
		recorreEnOrden(bloque); //Hijo Izquierdo
		TIPO_DATO_CHICO cantReg, i=0;
		cantReg = ((CNodo<CClave>*)m_rama)[posRama]->getCantRegistros();
		while ( i < cantReg )
		{	
			((CNodo<CClave>*)m_rama)[posRama]->procesarNodo(i); //Padre
			bloque = ((CNodo<CClave>*)m_rama)[posRama]->getSucesorDer(i);
			recorreEnOrden(bloque); //Hijo Derecho
			i++;
		}
		/*Aca podria eliminar la rama desde la posicion de este padre en adelante*/
		podarRama(posRama);
	}
	/*TODO 	VER EN QUE MOMENTO SE BORRA LA RAMA*/
}
/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::podarRama(TIPO_DATO posRama)
{
	itMapNodo it;
	
	it = m_rama.begin();
	it = m_rama.find(posRama);
	if(it!=m_rama.end())
		m_rama.erase(it);
}



template <class CClave >
bool CArbolB<CClave>::cambiarClave(CClave &claveVieja,CClave &claveNueva)
{
	TIPO_DATO raiz=0;
	limpiar();
	if(buscar(claveVieja,raiz))
	{
		((CNodoBase<CClave>*)m_rama[m_posRama-1])->cambiarClave(claveVieja,claveNueva);
		if(((CNodoBase<CClave>*)m_rama[m_posRama-1])->getNivel()==0)
			m_archIndice.write(((CHoja<CClave>*)m_rama[m_posRama-1]));
		else
			m_archIndice.write(((CNodo<CClave>*)m_rama[m_posRama-1]));
	}
	else
		cout<<"tendria que encontrarlo!!!!!!!!!!!!!!"<<endl;
	return false;
}

/*Este metodo busca el tama�o de espacio igual o mas parecido al que se ingresa por parametro
  una vez que encuentra el bloque lo borra de la clave, porque al salir va a ser modificado
*/
template <class CClave >
bool CArbolB<CClave>::obtenerNroBloque(CClave &espacioLibre,TIPO_DATO &nroBloqueOut)
{
	TIPO_DATO bloqueRaiz=0, tamanioEscribir;
	tamanioEscribir = espacioLibre.getClave();
//	m_encontro =false;
	if( this->buscar(espacioLibre,bloqueRaiz) ) 
	{//obtengo la clave de la rama
		if(!((CNodoBase<CClave>*)m_rama[m_posRama-1])->obtenerNroBloque(espacioLibre,nroBloqueOut,m_archivoListaSec))
			this->eliminar(espacioLibre);		
		else
		{
			this->escribirDisco();
			((CNodoBase<CClave>*)m_rama[m_posRama-1])->mostrar();
		}

	}
	else
	{//obtengo la clave del atributo m_claveAux
		if(((CClave*)&m_claveAux)->getClave()<tamanioEscribir)
			return false;// esto puede pasar por que es el unico nodo y no hay mas espacio para ingresar el nuevo registro
		//entonces no queda otra que crear otro bloque mas.
/*		
		if(!((CNodoBase<CClave>*)m_rama[m_posRama-1])->esRaiz())
		{			
			if(!((CNodoBase<CClave>*)m_rama[m_posRama-1])->obtenerNroBloque(m_claveAux,nroBloqueOut,m_archivoListaSec))
			{
				this->eliminar(m_claveAux);
				espacioLibre = m_claveAux;
			}
		}
		else 
*/		
		if(!((CNodoBase<CClave>*)m_rama[m_posRamaAux])->obtenerNroBloque(m_claveAux,nroBloqueOut,m_archivoListaSec))			
		{
			this->mostrarRama();
			this->eliminar(m_claveAux);
			this->mostrarRama();
		}
		else
		{
			this->escribirDisco();
			((CNodoBase<CClave>*)m_rama[m_posRamaAux])->mostrar();
		}
		espacioLibre = m_claveAux;
	}
	//this->escribirDisco();
	return true;
}

template <class CClave >
bool CArbolB<CClave>::eliminarElemVector(CClave &claveIn)
{
	TIPO_DATO bloqueRaiz=0;
	CClave claveAux;
	claveAux = claveIn;
	bool eliminado = false;
	if( this->buscar(claveIn,bloqueRaiz) ) 
	{
		eliminado = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->eliminarElemVector(claveAux.getCodProducto(0),m_archivoListaSec);
		((CNodoBase<CClave>*)m_rama[m_posRama-1])->mostrar();
	}
	if(((CNodoBase<CClave>*)m_rama[m_posRama-1])->getEliminar())
		eliminar(claveIn);
	else
		this->escribirDisco();
	return eliminado;
}

/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::leerBloque(TIPO_DATO nroBloque)
{
	MapNodo			rama;
	char bufferAux[TAMANIO_NODO]={};
	TIPO_DATO		tamanio;
	tamanio = m_archIndice.getTamanio();
	
	if(tamanio==0 || (tamanio/TAMANIO_NODO)<=nroBloque)
	{
		cout<<"El bloque que quiere leer no existe."<<endl;
		return;
	}
	this->incCosto(); //(CTO_PROC)
	//cargo el bloque en el nodo que corresponda
	if(this->m_archIndice.leerBloque(nroBloque,bufferAux) )
	{
		if(bufferAux[0]==(char)1)
		{
			cout<<"El bloque que se quiere inspeccionar no tiene datos."<<endl;
			return;
		}
		else
		{
			rama[0]= new CNodo<CClave>;		
			((CNodo<CClave>*)rama[0])->transformar(bufferAux);
		}
	}
	else
	{
		if(bufferAux[0]==(char)1)
		{
			cout<<"El bloque que se quiere inspeccionar no tiene datos."<<endl;
			return;
		}
		else
		{
			rama[0]= new CHoja<CClave>;
			((CHoja<CClave>*)rama[0])->transformar(bufferAux);
		}
	}
	
	((CNodoBase<CClave>*)rama[0])->setNroBloque(nroBloque);
	((CNodoBase<CClave>*)rama[0])->mostrar();
}
/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::leerClaveDeBloque(TIPO_DATO nroBloque ,CClave &claveAux)
{
	MapNodo			rama;
	char bufferAux[TAMANIO_NODO]={};
	TIPO_DATO		tamanio;
	tamanio = m_archIndice.getTamanio();
	
	if(tamanio==0 || (tamanio/TAMANIO_NODO)<=nroBloque)
	{
		cout<<"El bloque que quiere leer no existe."<<endl;
		return;
	}
	//cargo el bloque en el nodo que corresponda
	if(this->m_archIndice.leerBloque(nroBloque,bufferAux) )
	{
		if(bufferAux[0]==(char)1)
		{
			cout<<"El bloque que se quiere inspeccionar no tiene datos."<<endl;
			return;
		}
		else
		{
			rama[0]= new CNodo<CClave>;		
			((CNodo<CClave>*)rama[0])->transformar(bufferAux);
		}
	}
	else
	{
		if(bufferAux[0]==(char)1)
		{
			cout<<"El bloque que se quiere inspeccionar no tiene datos."<<endl;
			return;
		}
		else
		{
			rama[0]= new CHoja<CClave>;
			((CHoja<CClave>*)rama[0])->transformar(bufferAux);
		}
	}
	claveAux = ((CHoja<CClave>*)rama[0])->getClave(0);
}
/*-----------------------------------------------------------*/
/*template <class CClave >
bool CArbolB<CClave>::cambiarClave(CClave &claveVieja,CClave &claveNueva)
{
	((CNodoBase<CClave>*)m_rama[m_posRama-1])->cambiarClave(claveVieja,claveNueva);
	if(((CNodoBase<CClave>*)m_rama[m_posRama-1])->getNivel()==0)
		m_archIndice.write(((CHoja<CClave>*)m_rama[m_posRama-1]));
	else
		m_archIndice.write(((CNodo<CClave>*)m_rama[m_posRama-1]));
	return false;
}
*/
/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::buscarPrimeraHoja(TIPO_DATO &blqSig)
{
	TIPO_DATO	tamanio = 0;
	TIPO_DATO 	bloque	= 0; //Comienza por la raiz
	m_posRama 			= 0;		
	bool 	encontrado	= false;	
	
	tamanio 	= m_archIndice.getTamanio();	
	if(tamanio == 0 )
	{
		limpiar(); //deja la rama vacia
		cout<<"El indice que quiere leer esta vacio."<<endl;
		return ;
	}

	//Leo un nodo, lo pongo en la rama, si no es hoja 'baja' por el hijo menor
	while(!encontrado)
	{
		//limpiar(); //deja la rama vacia
		this->cargarBuffer(bloque);
		//m_posRama 	= 1; 	//'1' indica que en la pos cero hay un dato valido.			
		encontrado = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->esHoja();
		if(encontrado) //obtengo el menor de todos los hijos		
			blqSig = bloque;
		else
			bloque = ((CNodoBase<CClave>*)m_rama[m_posRama-1])->getSucesorIzq();		
	}
}
/*-----------------------------------------------------------*/
template <class CClave >
void CArbolB<CClave>::getVectorClavesSet(TIPO_DATO &blqSig, vector<void*> *unVector)
{	
	unVector->clear();	
	itVectorClavesHoja it;
	
	if(blqSig != FIN_SET_SECUENCIAL)
	{		
		//elimino la hoja de la rama para que la misma no crezca y contenga todo el indice en memoria
		this->podarRama(--m_posRama);
		this->cargarBufferSet(blqSig); //pone en la rama la hoja que se debe procesar.		
	
		CClave borrame;//es para chequear lo que lee
		//recorro el bloque cargando de claves el vector
		it = ((CHoja<CClave>*)m_rama[m_posRama-1])->clave.begin();	
		for(; it != ((CHoja<CClave>*)m_rama[m_posRama-1])->clave.end(); it++)
		{
			borrame = (*((CClave *)(*it).second));  //es para chequear lo que lee
			unVector->push_back(((*it).second));					
		} 	
		
		//obtengo el siguiente bloque
		blqSig = ((CHoja<CClave>*)m_rama[m_posRama-1])->getSigSetSec();
	}
}
/*-----------------------------------------------------------*/
#endif /*ARBOLB_H_*/
